<template>
  <el-card class="container">
    <el-form ref="form" :model="spu" :rules="rules" label-width="80px">
      <el-form-item label="SPU名称" prop="spuName">
        <el-input v-model="spu.spuName" placeholder="请输入SPU名称" />
      </el-form-item>
      <el-form-item label="SPU品牌" prop="tmId">
        <el-select v-model="spu.tmId" placeholder="请选择SPU品牌">
          <el-option
            v-for="tm in trademarkList"
            :key="tm.id"
            :label="tm.tmName"
            :value="tm.id"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="SPU描述" prop="description">
        <el-input
          v-model="spu.description"
          type="textarea"
          placeholder="请输入SPU名称"
        />
      </el-form-item>
      <el-form-item label="SPU图片" prop="spuImageList">
        <!--
          accept 允许上传的文件类型
          action 上传文件的地址
          on-preview 预览图片
          on-remove 删除图片
          on-success 上传图片成功
          before-upload 上传图片之前
          limit 限制图片上传最大数量
          class 通过类名来决定上传按钮的显示隐藏
         -->
        <el-upload
          accept="image/jpeg,image/jpg,image/png"
          :action="`${baseURL}/admin/product/fileUpload`"
          list-type="picture-card"
          :on-preview="handlePictureCardPreview"
          :on-remove="handleRemove"
          :on-success="handleAvatarSuccess"
          :before-upload="beforeAvatarUpload"
          :limit="limit"
          :file-list="formatSpuImageList"
          :class="{
            'save-spu-upload': spu.spuImageList.length === limit,
          }"
        >
          <i class="el-icon-plus"></i>
          <div slot="tip" class="el-upload__tip">
            只能上传jpg/png文件，且不超过500kb
          </div>
        </el-upload>
        <!-- 预览图片的容器 -->
        <el-dialog :visible.sync="dialogVisible" width="340px">
          <img class="save-spu-img" :src="dialogImageUrl" alt="" />
        </el-dialog>
      </el-form-item>
      <el-form-item label="销售属性" prop="spuSaleAttrList">
        <el-select
          v-model="spu.baseSaleAttr"
          :placeholder="`还剩${filterBaseSaleAttrList.length}个销售属性`"
        >
          <el-option
            v-for="baseSaleAttr in filterBaseSaleAttrList"
            :key="baseSaleAttr.id"
            :label="baseSaleAttr.name"
            :value="baseSaleAttr.name"
          />
        </el-select>
        <el-button
          :disabled="!spu.baseSaleAttr"
          type="primary"
          icon="el-icon-plus"
          @click="addSaleAttr"
        >
          添加销售属性
        </el-button>
        <el-table :data="spu.spuSaleAttrList" border class="table">
          <el-table-column
            type="index"
            label="序号"
            width="50"
            align="center"
          />
          <el-table-column prop="saleAttrName" label="属性名" width="80" />
          <el-table-column label="属性值列表">
            <template v-slot="{ row, $index }">
              <el-tag
                v-for="(saleAttrValue, index) in row.spuSaleAttrValueList"
                :key="index"
                closable
                class="save-spu-tag"
              >
                {{ saleAttrValue.saleAttrValueName }}
              </el-tag>

              <el-input
                v-if="row.isEdit"
                v-model="spu.saleAttrValueName"
                :ref="$index"
                placeholder="请输入属性值"
                size="mini"
                class="save-spu-input"
                @blur="addSaleAttrValue(row)"
              />
              <el-button
                v-else
                icon="el-icon-plus"
                size="mini"
                @click="showEdit(row, $index)"
              >
                添加属性值
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="80">
            <template v-slot="{ $index }">
              <el-button
                type="danger"
                icon="el-icon-delete"
                size="mini"
                @click="spu.spuSaleAttrList.splice($index, 1)"
              />
            </template>
          </el-table-column>
        </el-table>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="submitForm">
          确定
        </el-button>
        <el-button @click="$emit('setIsShow', 1)">
          取消
        </el-button>
      </el-form-item>
    </el-form>
  </el-card>
</template>

<script>
import { mapState } from "vuex";
export default {
  name: "SaveSpu",
  props: {
    currentSpu: {
      type: Object,
    },
  },
  data() {
    const validator = (ruel, value, callback) => {
      // value -> spuSaleAttrList 销售属性列表
      // [{ spuSaleAttrValueList: 销售属性值列表}]
      // 至少添加一个销售属性
      if (!value.length) {
        callback("至少添加一个属性");
        return;
      }
      // 每个销售属性至少添加一个销售属性值
      if (
        !value.every((saleAttr) => saleAttr.spuSaleAttrValueList.length > 0)
      ) {
        callback("每个销售属性至少添加一个销售属性");
        return;
      }
      // 必须调用
    };

    return {
      dialogImageUrl: "",
      dialogVisible: false,
      trademarkList: [],
      // 基础销售属性列表
      baseSaleAttrList: [],
      spu: {
        // 输入的销售属性值
        saleAttrValueName: "",
        // 选中的销售属性
        baseSaleAttr: "",
        // spu名称
        spuName: "",
        // 品牌
        tmId: "",
        // 描述
        description: "",
        // 图片列表
        spuImageList: [],
        // 销售属性列表
        spuSaleAttrList: [],
        // 后面会覆盖前面的
        ...this.currentSpu,
      },
      rules: {
        // spu名称
        spuName: [
          { required: true, message: "请输入spu名称", trigger: "blur" },
        ],
        // 品牌
        tmId: [{ required: true, message: "请选择spu品牌" }],
        // 描述
        description: [
          { required: true, message: "请输入spu描述", trigger: "blur" },
        ],
        // 图片列表
        spuImageList: [{ required: true, message: "请上传spu图片" }],
        // 销售属性列表
        spuSaleAttrList: [{ required: true, validator }],
      },
      // 请求地址前缀
      baseURL: process.env.VUE_APP_BASE_API,
      // 图片上传的最大数量
      limit: 10,
    };
  },
  computed: {
    ...mapState("category", ["category3Id"]),
    filterBaseSaleAttrList() {
      return this.baseSaleAttrList.filter((baseSaleAttr) => {
        // 在表格中的销售属性列表中，找是否存在基础销售属性的值
        // 如果存在，说明这个基础销售属性的值被添加到表格中的销售属性列表中
        // 将添加进去的过滤掉
        return !this.spu.spuSaleAttrList.find(
          (saleAttr) => saleAttr.saleAttrName === baseSaleAttr.name
        );
      });
    },
    formatSpuImageList() {
      return this.spu.spuImageList.map((img) => {
        return {
          name: img.imgName,
          url: img.imgUrl,
          // 添加uid  为了让上传的图片不会抖动
          // 保证uid前后值一样
          uid: img.uid || img.id,
        };
      });
    },
  },
  async mounted() {
    /*
      Promise.resolve()
        返回一个promise对象，这个promise对象的状态看接受的参数
          如果接受参数是一个失败状态的promise，就是失败状态
          反之，就是成功状态
      Promise.reject() 返回一个失败状态promise对象
      Promise.all([promise1, promise2, ...])
        当所有promise对象的状态都成功了，Promise.all返回值promise的对象才是成功状态
        只要有一个promise对象的状态是失败的，Promise.all返回值promise的对象就是失败状态
          只有所有都成功才成功，只要有一个失败就失败
      Promise.allSettled([promise1, promise2, ...])
        一定会返回一个成功的promise对象，内部会保存所有promise对象的结果值
    */

    try {
      const { id } = this.spu;

      let promise = [
        this.$API.trademark.reqGetAllTrademarkList(),
        this.$API.spu.reqGetBaseSaleAttrList(),
      ];

      // 更新SPU
      // 需要额外补发两个请求
      if (id) {
        promise = promise.concat([
          this.$API.spu.reqGetSpuImageList(id),
          this.$API.spu.reqGetSpuSaleAttrList(id),
        ]);
      }
      const [
        trademarkListResponse,
        baseSaleAttrListResponse,
        spuImageListResponse,
        spuSaleAttrListResponse,
      ] = await Promise.all(promise);

      this.trademarkList = trademarkListResponse.data;
      this.basrSaleAttrList = basrSaleAttrListResponse.data;

      //判断有无
      if (spuImageListResponse) {
        this.trademarkList = trademarkListResponse.data;
        this.baseSaleAttrList = baseSaleAttrListResponse.data;
      }
    } catch (e) {
      this.$message({
        type: "error",
        message: "获取数据失败",
      });
    }
  },
  methods: {
    // 提交表单
    submitForm() {
      this.$refs.form.validate(async (valid) => {
        if (valid) {
          const { spuName, tmId, description, spuImageList, spuSaleAttrList } =
            this.spu;
          const { category3Id } = this;

          const options = {
            spuName,
            tmId,
            description,
            spuImageList,
            spuSaleAttrList,
            category3Id,
          };

          if (id) {
            await this.$API.spu.reqUpdateSpu({
              ...options,
              id
            })
          } else {
            await this.$API.spu.reqSaveSpu(options)
          }

          this.$message({
            type: "success",
            message: `${id ? '修改' : '添加'}spu成功`
          });
          this.$emit("setIsShow", 1);
        }
      });
    },
    // 添加售属性值
    addSaleAttrValue(row) {
      const { saleAttrValueName } = this.spu;

      if (saleAttrValueName) {
        // 添加
        // 销售属性值列表
        row.spuSaleAttrValueList.push({
          baseSaleAttrId: row.baseSaleAttrId,
          saleAttrValueName, // 销售属性值名称
        });
        // 清空输入框数据
        this.spu.saleAttrValueName = "";
      }
      // 显示模式
      row.isEdit = false;
    },
    // 显示编辑模式
    showEdit(row, index) {
      // row.isEdit = true;
      this.$set(row, 'isEdit', true)
      this.$nextTick(() => {
        this.$refs[indx].focus();
      });
    },
    // 添加销售属性值
    addSaleAttr() {
      const { baseSaleAttr } = this.spu
      this.spu.spuSaleAttrList.push({
        // 查找baseSaleAttr 的id
        baseSaleAttrId: this.baseSaleAttrList.find(
          saleAttr => saleAttr.name === baseSaleAttr
        ).id,
        // 销售属性名
        saleAttrName: baseSaleAttr,
        // 销售属性值列表
        spuSaleAttrValueList: [],
        isEdit: false
      });

      // 为了清空select选中值
      this.spu.baseSaleAttr = "";
    },
    // 删除图片的回调
    handleRemove(file, fileList) {
      // 删除默认情况下：会从效果上删除图片，但是数据没有删除
      // 手动删除数据
      // console.log(file.response.data)
      const url = file.response ? file.response.data : file.url
      this.spu.spuImageList = this.spu.spuImageList.filter(
        (img) => img.imgUrl !== url
      );
    },
    // 预览图片的回调
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url;
      this.dialogVisible = true;
    },
    // 上传成功触发的回调
    handleAvatarSuccess(res, file) {
      // 添加一个对象 - 和服务器要求上传的数据结构一致
      this.spu.spuImageList.push({
        imgName: file.name,
        imgUrl: res.data,
        uid: file.uid
      });
      // 清空表单校验结果
      this.$refs.form.clearValidate(["spuImageList"]);
    },
    // 上传之前触发的回调
    beforeAvatarUpload(file) {
      // 对上传图片的类型和大小进行限制
      const fileTypes = ["image/jpeg", "image/jpg", "image/png"];

      const isValidFileType = fileTypes.includes(file.type);
      const isValidFileSize = file.size / 1024 < 500;

      if (!isValidFileType) {
        this.$message.error("上传头像图片只能是 JPG 或 PNG 格式!");
      }
      if (!isValidFileSize) {
        this.$message.error("上传头像图片大小不能超过 500KB!");
      }

      // 返回值true，通过，可以上传图片
      // 返回值false，不通过，不会上传图片
      return isValidFileType && isValidFileSize;
    },
  },
};
</script>

<style lang="sass" scoped>
.save-spu-img
  width: 300px
.save-spu-input
  width: 150px
.save-spu-tag
  margin-right: 10px
</style>
